#ifdef UTIL_PLATFORM_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")

#include "lang/String.h"
#include "net/Socket.h"
#include "net/InetSocketAddress.h"
using namespace yzrilyzr_lang;
using namespace yzrilyzr_io;
namespace yzrilyzr_net{
	EBCLASS(WinImplData){
	public:
	SOCKET clientSocket;
	};

	class WinSockOutputStream :public yzrilyzr_io::OutputStream{
		private:
		Socket * socket=nullptr;
		public:
		WinSockOutputStream(Socket * soc) :socket(soc){
		}
		~WinSockOutputStream(){
			close();
		}
		void write(int32_t b)override{
			if(socket->isOutputShutdown()){
				throw SocketException("Socket output is shutdown");
			}
			WinImplData & imp=*static_cast<WinImplData *>(socket->implData);
			char by=b;
			int result=send(imp.clientSocket, &by, 1, 0);
			if(result == SOCKET_ERROR){
				throw SocketException(String("Send failed: ") + WSAGetLastError());
			}
		}
		void write(const yzrilyzr_array::ByteArray & b, u_index off, u_index len)override{
			if(socket->isOutputShutdown()){
				throw SocketException("Socket output is shutdown");
			}
			WinImplData & imp=*static_cast<WinImplData *>(socket->implData);
			int result=send(imp.clientSocket, reinterpret_cast<char *>(b._array + off), len, 0);
			if(result == SOCKET_ERROR){
				throw SocketException(String("Send failed: ") + WSAGetLastError());
			}
		}
		void close()override{
			socket->close();
		}
	};
	class WinSockInputStream :public yzrilyzr_io::InputStream{
		private:
		Socket * socket=nullptr;
		public:
		WinSockInputStream(Socket * soc) :socket(soc){
		}
		~WinSockInputStream(){
			close();
		}
		int32_t read()override{
			if(socket->isInputShutdown())return -1;
			WinImplData & imp=*static_cast<WinImplData *>(socket->implData);
			char by=0;
			int result=recv(imp.clientSocket, &by, 1, 0);
			if(result == SOCKET_ERROR){
				throw SocketException(String("Receive failed: ") + WSAGetLastError());
			} else if(result == 0){
				return -1;
			}
			return by & 0xff;
		}
		u_index read(yzrilyzr_array::ByteArray & b, u_index off, u_index len)override{
			if(socket->isInputShutdown())return -1;
			WinImplData & imp=*static_cast<WinImplData *>(socket->implData);
			int result=recv(imp.clientSocket, reinterpret_cast<char *>(b._array + off), len, 0);
			if(result == SOCKET_ERROR){
				throw SocketException(String("Receive failed: ") + WSAGetLastError());
			} else if(result == 0){
				return -1;
			}
			return result;
		}
		void close()override{
			socket->close();
		}
		u_index available()override{
			if(socket->isInputShutdown())return 0;
			WinImplData & imp=*static_cast<WinImplData *>(socket->implData);
			u_long bytesAvailable=0;
			int result=ioctlsocket(imp.clientSocket, FIONREAD, &bytesAvailable);
			if(result == SOCKET_ERROR){
				throw SocketException(String("ioctlsocket failed: ") + WSAGetLastError());
			}
			return static_cast<u_index>(bytesAvailable);
		}
	};
	Socket::Socket(){
		static std::once_flag wsaInitFlag;
		std::call_once(wsaInitFlag, [](){
			WSADATA wsaData;
			if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){
				throw SocketException("WSAStartup failed");
			}
		});
		implData=new WinImplData{};
		 // 创建 socket
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		imp.clientSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if(imp.clientSocket == INVALID_SOCKET){
			throw SocketException(String("Socket creation failed: ") + WSAGetLastError());
		}
		created=true;
	}
	Socket::~Socket(){
		close();
		if(implData){
			WinImplData * ptr=static_cast<WinImplData *>(implData);
			delete ptr;
			implData=nullptr;
		}
	}
	void Socket::bind(std::shared_ptr<SocketAddress> addr){
		if(isClosed())
			throw new SocketException("Socket is closed");
		if(isBound())
			throw new SocketException("Already bound");

		auto inetAddr=std::dynamic_pointer_cast<InetSocketAddress>(addr);
		if(!inetAddr){
			throw IllegalArgumentException("Unsupported address type");
		}

		std::unique_lock<std::shared_mutex> lock(stateLock);
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		// 绑定地址
		sockaddr_in localAddr{};
		localAddr.sin_family=AF_INET;
		localAddr.sin_port=htons(inetAddr->getPort());
		inet_pton(AF_INET, inetAddr->getAddress()->toFullString().c_str(),
				  &localAddr.sin_addr);
		if(::bind(imp.clientSocket, (sockaddr *)&localAddr, sizeof(localAddr)) == SOCKET_ERROR){
			throw SocketException(String("Bind failed") + WSAGetLastError());
		}
		bound=true;
	}
	void Socket::connect(std::shared_ptr<SocketAddress> addr, int32_t timeout){
		auto inetAddr=std::dynamic_pointer_cast<InetSocketAddress>(addr);
		if(!inetAddr){
			throw IllegalArgumentException("Unsupported address type");
		}
		std::unique_lock<std::shared_mutex> lock(stateLock);
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		// 设置服务器地址.
		sockaddr_in serverAddr{};
		serverAddr.sin_family=AF_INET;
		serverAddr.sin_port=htons(inetAddr->getPort());
		inet_pton(AF_INET, inetAddr->getAddress()->toFullString().c_str(), &serverAddr.sin_addr);
		// 连接服务器
		if(::connect(imp.clientSocket, (sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR){
			closesocket(imp.clientSocket);
			throw SocketException(String("Connection failed: ") + WSAGetLastError());
		}
		connected=true;
	}
	void Socket::setSoTimeout(int32_t timeout){
		if(isClosed())
			throw SocketException("Socket is closed");
		if(timeout < 0)
			throw IllegalArgumentException("timeout can't be negative");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		DWORD timeoutMs=timeout;
		if(setsockopt(imp.clientSocket, SOL_SOCKET, SO_RCVTIMEO,
					  (char *)&timeoutMs, sizeof(timeoutMs)) == SOCKET_ERROR){
			throw SocketException("Set SO_RCVTIMEO failed");
		}
		if(setsockopt(imp.clientSocket, SOL_SOCKET, SO_SNDTIMEO,
					  (char *)&timeoutMs, sizeof(timeoutMs)) == SOCKET_ERROR){
			throw SocketException("Set SO_SNDTIMEO failed");
		}
	}
	void Socket::setKeepAlive(bool on){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		BOOL option=on?TRUE:FALSE;  // 更明确的类型转换
		if(setsockopt(imp.clientSocket, SOL_SOCKET, SO_KEEPALIVE,
					  (char *)&option, sizeof(option)) == SOCKET_ERROR){
			throw SocketException("Set SO_KEEPALIVE failed");
		}
	}
	void Socket::setOOBInline(bool on){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		BOOL option=on?TRUE:FALSE;
		if(setsockopt(imp.clientSocket, SOL_SOCKET, SO_OOBINLINE,
					  (char *)&option, sizeof(option)) == SOCKET_ERROR){
			throw SocketException("Set SO_OOBINLINE failed");
		}
	}
	void Socket::setReuseAddress(bool on){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		BOOL option=on?TRUE:FALSE;
		if(setsockopt(imp.clientSocket, SOL_SOCKET, SO_REUSEADDR,
					  (char *)&option, sizeof(option)) == SOCKET_ERROR){
			throw SocketException("Set SO_REUSEADDR failed");
		}
	}
	void Socket::setSoLinger(bool on, int32_t linger){
		if(isClosed())
			throw SocketException("Socket is closed");

		WinImplData & imp=*static_cast<WinImplData *>(implData);

		struct linger lingerOpt;

		if(on){
			if(linger < 0){
				throw IllegalArgumentException("invalid value for SO_LINGER");
			}
			if(linger > 65535)
				linger=65535;

			lingerOpt.l_onoff=1;    // 启用linger
			lingerOpt.l_linger=static_cast<u_short>(linger);
		} else{
			lingerOpt.l_onoff=0;    // 禁用linger
			lingerOpt.l_linger=0;   // 这个值在禁用时被忽略
		}

		if(setsockopt(imp.clientSocket, SOL_SOCKET, SO_LINGER,
					  (char *)&lingerOpt, sizeof(lingerOpt)) == SOCKET_ERROR){
			throw SocketException("Set SO_LINGER failed");
		}
	}
	void Socket::setTcpNoDelay(bool on){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		BOOL option=on?TRUE:FALSE;
		if(setsockopt(imp.clientSocket, IPPROTO_TCP, TCP_NODELAY,
					  (char *)&option, sizeof(option)) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Set TCP_NODELAY failed: ") + static_cast<int>(error));
		}
	}
	void Socket::setSendBufferSize(int32_t size){
		if(isClosed())
			throw SocketException("Socket is closed");
		if(size <= 0)
			throw IllegalArgumentException("Send buffer size must be positive");

		WinImplData & imp=*static_cast<WinImplData *>(implData);
		int bufferSize=size;
		if(setsockopt(imp.clientSocket, SOL_SOCKET, SO_SNDBUF,
					  (char *)&bufferSize, sizeof(bufferSize)) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Set SO_SNDBUF failed: ") + static_cast<int>(error));
		}

		// 验证实际设置的缓冲区大小
		int actualSize=0;
		int sizeLen=sizeof(actualSize);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_SNDBUF,
					  (char *)&actualSize, &sizeLen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_SNDBUF failed: ") + static_cast<int>(error));
		}

		// 系统可能会调整缓冲区大小，通常会是请求值的2倍
		// 这里可以选择记录日志或进行其他处理
	}
	void Socket::setReceiveBufferSize(int32_t size){
		if(isClosed())
			throw SocketException("Socket is closed");
		if(size <= 0)
			throw IllegalArgumentException("Receive buffer size must be positive");

		WinImplData & imp=*static_cast<WinImplData *>(implData);
		int bufferSize=size;
		if(setsockopt(imp.clientSocket, SOL_SOCKET, SO_RCVBUF,
					  (char *)&bufferSize, sizeof(bufferSize)) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Set SO_RCVBUF failed: ") + static_cast<int>(error));
		}

		// 验证实际设置的缓冲区大小
		int actualSize=0;
		int sizeLen=sizeof(actualSize);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_RCVBUF,
					  (char *)&actualSize, &sizeLen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_RCVBUF failed: ") + static_cast<int>(error));
		}
	}
	void Socket::setTrafficClass(int32_t tc){
		if(isClosed())
			throw SocketException("Socket is closed");
		if(tc < 0 || tc > 255)
			throw IllegalArgumentException("Traffic class must be between 0 and 255");

		WinImplData & imp=*static_cast<WinImplData *>(implData);
		int tos=tc;

		// 对于IPv4使用IP_TOS
		if(setsockopt(imp.clientSocket, IPPROTO_IP, IP_TOS,
					  (char *)&tos, sizeof(tos)) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			// 有些系统可能不支持IP_TOS，这里可以选择记录日志或忽略特定错误
			if(error != WSAENOPROTOOPT){ // 如果协议不支持，可以选择不抛出异常
				throw SocketException(String("Set IP_TOS failed: ") + static_cast<int>(error));
			}
			// 对于不支持的选项，可以选择静默失败或记录日志
		}
	}
	int32_t Socket::getSoTimeout(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		DWORD timeout=0;
		int optlen=sizeof(timeout);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_RCVTIMEO,
					  (char *)&timeout, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_RCVTIMEO failed: ") + static_cast<int>(error));
		}
		return static_cast<int32_t>(timeout);
	}
	int32_t Socket::getSoLinger(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		struct linger lingerOpt;
		int optlen=sizeof(lingerOpt);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_LINGER,
					  (char *)&lingerOpt, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_LINGER failed: ") + static_cast<int>(error));
		}
		if(lingerOpt.l_onoff == 0)return -1;
		return static_cast<int32_t>(lingerOpt.l_linger);
	}
	bool Socket::getKeepAlive(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		BOOL option=FALSE;
		int optlen=sizeof(option);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_KEEPALIVE,
					  (char *)&option, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_KEEPALIVE failed: ") + static_cast<int>(error));
		}
		return option != FALSE;
	}
	bool Socket::getOOBInline(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		BOOL option=FALSE;
		int optlen=sizeof(option);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_OOBINLINE,
					  (char *)&option, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_OOBINLINE failed: ") + static_cast<int>(error));
		}
		return option != FALSE;
	}
	bool Socket::getReuseAddress(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		BOOL option=FALSE;
		int optlen=sizeof(option);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_REUSEADDR,
					  (char *)&option, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_REUSEADDR failed: ") + static_cast<int>(error));
		}
		return option != FALSE;
	}
	bool Socket::getTcpNoDelay(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		BOOL option=FALSE;
		int optlen=sizeof(option);
		if(getsockopt(imp.clientSocket, IPPROTO_TCP, TCP_NODELAY,
					  (char *)&option, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get TCP_NODELAY failed: ") + static_cast<int>(error));
		}
		return option != FALSE;
	}
	int32_t Socket::getSendBufferSize(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		int size=0;
		int optlen=sizeof(size);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_SNDBUF,
					  (char *)&size, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_SNDBUF failed: ") + static_cast<int>(error));
		}
		return static_cast<int32_t>(size);
	}
	int32_t Socket::getReceiveBufferSize(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		int size=0;
		int optlen=sizeof(size);
		if(getsockopt(imp.clientSocket, SOL_SOCKET, SO_RCVBUF,
					  (char *)&size, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			throw SocketException(String("Get SO_RCVBUF failed: ") + static_cast<int>(error));
		}
		return static_cast<int32_t>(size);
	}
	int32_t Socket::getTrafficClass(){
		if(isClosed())
			throw SocketException("Socket is closed");
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		int tos=0;
		int optlen=sizeof(tos);
		if(getsockopt(imp.clientSocket, IPPROTO_IP, IP_TOS,
					  (char *)&tos, &optlen) == SOCKET_ERROR){
			DWORD error=WSAGetLastError();
			// 如果协议不支持IP_TOS，返回默认值0
			if(error == WSAENOPROTOOPT){
				return 0;
			}
			throw SocketException(String("Get IP_TOS failed: ") + static_cast<int>(error));
		}
		return static_cast<int32_t>(tos);
	}
	std::shared_ptr<InputStream> Socket::getInputStream(){
		if(isClosed())
			throw SocketException("Socket is closed");
		if(!isConnected())
			throw SocketException("Socket is not connected");
		if(isOutputShutdown())
			throw SocketException("Socket output is shutdown");
		if(in == nullptr){
			in=std::make_shared<WinSockInputStream>(this);
		}
		return in;
	}
	std::shared_ptr<OutputStream> Socket::getOutputStream(){
		if(isClosed())
			throw SocketException("Socket is closed");
		if(!isConnected())
			throw SocketException("Socket is not connected");
		if(isInputShutdown())
			throw SocketException("Socket input is shutdown");
		if(out == nullptr){
			out=std::make_shared<WinSockOutputStream>(this);
		}
		return out;
	}
	void Socket::close(){
		std::unique_lock<std::shared_mutex> lock(stateLock);
		if(closed)return;
		if(created){
			WinImplData & imp=*static_cast<WinImplData *>(implData);
			if(imp.clientSocket != INVALID_SOCKET){
				closesocket(imp.clientSocket);
				imp.clientSocket=INVALID_SOCKET;
			}
		}
		closed=true;
	}
	void Socket::shutdownInput(){
		if(isClosed())
			throw SocketException("Socket is closed");
		if(!isConnected())
			throw SocketException("Socket is not connected");
		if(isInputShutdown())
			throw SocketException("Socket input is already shutdown");
		std::unique_lock<std::shared_mutex> lock(stateLock);
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		int result=shutdown(imp.clientSocket, SD_RECEIVE);
		if(result == SOCKET_ERROR){
			throw SocketException(String("shutdown input failed: ") + WSAGetLastError());
		}
		shutIn=true;
	}
	void Socket::shutdownOutput(){
		if(isClosed())
			throw SocketException("Socket is closed");
		if(!isConnected())
			throw SocketException("Socket is not connected");
		if(isOutputShutdown())
			throw SocketException("Socket output is already shutdown");
		std::unique_lock<std::shared_mutex> lock(stateLock);
		WinImplData & imp=*static_cast<WinImplData *>(implData);
		int result=shutdown(imp.clientSocket, SD_SEND);
		if(result == SOCKET_ERROR){
			throw SocketException(String("shutdown output failed: ") + WSAGetLastError());
		}
		shutOut=true;
	}
}
#endif // _WIN32